<?php
namespace App\GraphQL\Mutations\Group;

use App\Models\Group;
use App\Models\GroupMember;
use App\Models\User;
use GraphQL\Type\Definition\ResolveInfo;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use Nuwave\Lighthouse\Support\Contracts\GraphQLContext;
use App\Models\GroupPolicy;
use App\Models\GroupPolicyRule;
use App\Models\GlobalStatistical;
use Illuminate\Support\Facades\DB;
use App\Models\AgentStatistical;
use App\Models\MerchantStatistical;
use App\Models\DistributorStatistical;

class Create
{

    /**
     * Return a value for the field.
     *
     * @param null $rootValue
     *            Usually contains the result returned from the parent field. In this case, it is always `null`.
     * @param mixed[] $args
     *            The arguments that were passed into the field.
     * @param \Nuwave\Lighthouse\Support\Contracts\GraphQLContext $context
     *            Arbitrary data that is shared between all fields of a single query.
     * @param \GraphQL\Type\Definition\ResolveInfo $resolveInfo
     *            Information about the query itself, such as the execution state, the field name, path to the field from the root, and more.
     * @return mixed
     */
    public function __invoke($rootValue, array $args, GraphQLContext $context, ResolveInfo $resolveInfo)
    {
        DB::transaction(function () use ($args) {

            $data = $args['input'];
            $authUser = auth()->user();
            $members = collect($data['members']);
            $data['people_total'] = $members->count();
            $data['user_id'] = $authUser->id;
            $cate = $data['cate'];
            $this->validate($data);
            $users = User::whereIn('id', collect($data['members'])->pluck('user_id')->unique())->get();
            $members = collect($data['members'])->filter(function ($item) use ($cate) {
                if ($cate == 'DEVICE') {
                    return in_array($item['role'], [
                        'DISTRIBUTOR',
                        'MERCHANT'
                    ]);
                } else if ($cate == 'STAFF') {
                    return $item['role'] === 'STAFF';
                }
                return false;
            })->map(function ($item) use (&$users) {
                $user = $users->where('id', $item['user_id'])
                    ->first();
                $item['avatar_url'] = $user->avatar_url;
                return new GroupMember($item);
            });
            $data['people_total'] = $members->count();
            // 创建分组
            $group = Group::create($data);
            // 保存成员
            $group->members()->saveMany($members);
            // 更新全局统计
            $globalStatistical = GlobalStatistical::first();
            if (!$globalStatistical) {
                $globalStatistical = GlobalStatistical::create();
            }
            $globalStatistical->increment('group_count');
            if ($cate === 'DEVICE') {
                // 更新代理商(群组创建者)设备统计
                $agentStatistical = AgentStatistical::firstOrCreate([
                    'user_id' => $authUser->id
                ]);
                $agentStatistical->increment('link_group_count');
                // 更新终端伙伴设备统计
                if ($group->merchant) {
                    $merchantStatistical = MerchantStatistical::firstOrCreate([
                        'user_id' => $group->merchant->id
                    ]);
                    $merchantStatistical->increment('link_group_count');
                }
                // 更新分销商统计
                $distributors = $group->members()
                    ->where('role', 'DISTRIBUTOR')
                    ->get();
                $distributors->map(function ($distributor) {
                    $distributorStatistical = DistributorStatistical::firstOrCreate([
                        'user_id' => $distributor->user_id
                    ]);
                    $distributorStatistical->increment('link_group_count');
                });
            } else {
                // 更新终端伙伴设备统计
                $merchantStatistical = MerchantStatistical::firstOrCreate([
                    'user_id' => $authUser->id
                ]);
                $merchantStatistical->increment('link_group_count');
            }
        });
        return [
            'status' => '200',
            'message' => '创建成功'
        ];
    }

    public function validate($data)
    {
        $cates = [
            'DEVICE',
            'STAFF'
        ];
        $rules = [
            'name' => [
                'required',
                'max:18'
            ],
            'cate' => [
                'required',
                Rule::in($cates)
            ],
            'policy_id' => [
                'nullable',
                'numeric'
            ],
            'members' => [
                'nullable',
                'array'
            ],
            'members.*.user_id' => [
                'required',
                'numeric'
            ],
            'members.*.address' => [
                'required'
            ],
            'members.*.address_detail' => [
                'required'
            ],
            'members.*.name' => [
                'required'
            ],
            'members.*.phone' => [
                'required'
            ],
            'members.*.role' => [
                'required',
                'in:DISTRIBUTOR,MERCHANT,STAFF'
            ],
            'members.*.policy_rule_id' => [
                'nullable',
                'numeric'
            ]
        ];
        if ($data['cate'] == 'STAFF') {
            $rules['device_group_id'] = [
                'required',
                'integer'
            ];
        }
        $messages = [
            'name.required' => '名称不能为空',
            'name.max' => '名称不能超过18个字',
            'cate.required' => '分类不能为空',
            'cate.in' => '分类不能超出限制',
            'policy_id.numeric' => '策略ID为数值',
            'members.array' => '成员为数组',
            'members.*.user_id.required' => '成员ID不能为空',
            'members.*.user_id.numeric' => '成员ID为数值',
            'members.*.address.required' => '成员地址不能为空',
            'members.*.address_detail.required' => '成员详细地址不能为空',
            'members.*.name.required' => '成员联系人不能为空',
            'members.*.phone.required' => '成员联系电话不能为空',
            'members.*.role.required' => '成员角色不能为空',
            'members.*.policy_rule_id.numeric' => '成员策略规则为数值'
        ];
        $validate = Validator::make($data, $rules, $messages);
        if ($validate->fails()) {
            throw new \InvalidArgumentException($validate->messages()->first());
        }
        // 验证规则与群组是否为同一类型
        if ($data['policy_id']) {
            $policy = GroupPolicy::find($data['policy_id']);
            if (! $policy) {
                throw new \Exception('策略不存在');
            }
            if ($policy->cate !== $data['cate']) {
                throw new \Exception('策略类型与群组类型不匹配');
            }
        }
        $members = collect($data['members']);
        // 验证终端伙伴是否只有一个
        if ($members->where('role', 'MERCHANT')->count() > 1) {
            throw new \Exception('终端伙伴只允许存在一个');
        }
        // 验证用户是否都存在
        $users = User::select('id')->whereIn('id', $members->pluck('user_id')
            ->unique())
            ->get();
        if ($users->count() !== $members->count()) {
            throw new \Exception('用户重复或者不存在');
        }
        // 去重过滤空 验证策略规则数量
        $rules = $members->filter(function ($value, $key) {
            return $value['policy_rule_id'] ? TRUE : FALSE;
        })
            ->pluck('policy_rule_id')
            ->unique();
        $groupRules = GroupPolicyRule::where('group_policy_id', $data['policy_id'])->whereIn('id', $rules)->get();
        if ($groupRules->count() !== $rules->count()) {
            throw new \Exception('策略规则不存在');
        }
        // 验证每个规则分类是否与角色一直
        $members->map(function ($item) use (&$groupRules) {
            if ($item['policy_rule_id']) {
                $rule = $groupRules->where('id', $item['policy_rule_id'])
                    ->first();
                if ($item['role'] !== $rule->cate) {
                    throw new \Exception('角色与策略分类不对称!');
                }
            }
        });
        return true;
    }
}
